#include "Svar.h"

#include <yaml-cpp/yaml.h>
#include "json.hpp"

namespace sv {

// 将 JSON 对象转换为 YAML 字符串
void json_to_yaml(const nlohmann::json& j, YAML::Emitter& out) {
    if (j.is_null()) {
        out << YAML::Null;
    } else if (j.is_boolean()) {
        out << j.get<bool>();
    } else if (j.is_number()) {
        out << j.get<double>();
    } else if (j.is_string()) {
        out << j.get<std::string>();
    } else if (j.is_array()) {
        out << YAML::BeginSeq;
        for (const auto& elem : j) {
            json_to_yaml(elem, out);
        }
        out << YAML::EndSeq;
    } else if (j.is_object()) {
        out << YAML::BeginMap;
        for (const auto& kv : j.items()) {
            out << YAML::Key << kv.key() << YAML::Value;
            json_to_yaml(kv.value(), out);
        }
        out << YAML::EndMap;
    }
}


/// Yaml save and load class
class Yaml final{
public:
    static Svar load(const std::string& input){
        YAML::Node node=YAML::Load(input);
        //std::cout<<node<<std::endl;

        return toSvar(node);
    }

    static std::string dump(Svar var) {
        nlohmann::json j;
        YAML::Emitter out;

        j = nlohmann::json::parse(var.dump_json());
        json_to_yaml(j, out);

        return out.c_str();
    }

    static Svar toSvar(const YAML::Node& node){
        if(!node.IsDefined()) return Svar::Undefined();
        if(node.IsScalar()) return Svar(node.Scalar());
        if(node.IsSequence()){
            std::vector<Svar> vars;
            vars.reserve(node.size());
            for(auto it:node)
                vars.push_back(toSvar(it));
            return vars;
        }
        if(node.IsMap()) {
            std::map<std::string,Svar> vars;
            for(YAML::const_iterator it=node.begin();it!=node.end();++it)
            {
                vars[it->first.as<std::string>()] = toSvar(it->second);
                //std::cout<<it->first<<it->second << std::endl;;
            }
            return vars;
        }

        return Svar::Undefined();
    }

    static YAML::Node toNode(Svar var){
        (void) var;
        return YAML::Node();
    }
};

REGISTER_SVAR_MODULE(Yaml) {
    SvarClass::Class<Yaml>()
            .def_static("load", &Yaml::load)
            .def_static("dump", &Yaml::dump);

    Svar::instance()["__builtin__"].set("Yaml", SvarClass::instance<Yaml>());
}

} // end of namespace sv
